package org.jeecg.modules.act.wx;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.wx.*;
import org.jeecg.modules.act.entity.ActPay;
import org.jeecg.modules.act.entity.ActUserRecord;
import org.jeecg.modules.act.service.IActPayService;
import org.jeecg.modules.act.service.IActUserRecordService;
import org.jeecg.modules.act.vo.ActPayVo;
import org.jeecg.modules.act.vo.ActivityVo;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;

@RestController
@RequestMapping("/wx/")
@Api(tags = "wx_支付接口", value = "wx_支付接口")
public class PayController {

    @Resource
    private IActPayService payService;

    /**
     * 小程序支付
     */
    @ApiOperation(value = "支付", notes = "支付")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "openId", value = "openid", required = true),
            @ApiImplicitParam(name = "orderNo", value = "订单号", required = true),
            @ApiImplicitParam(name = "pay", value = "支付金额", required = true),
    })
    @PostMapping(value = "pay")
    public Result pay(HttpServletRequest request, String openId, String orderNo, BigDecimal pay) {
        Result res = new Result();
        try {
            if ("".equals(orderNo) || "undefined".equals(orderNo)) {
                res.setCode(1);
                res.setMessage("订单信息错误");
                return res;
            }
            //转换为分
            QueryWrapper<ActPay> wrapper = new QueryWrapper<>(new ActPay());
            wrapper.eq("order_no", orderNo);
            ActPay actPay = payService.getOne(wrapper);
            if (!pay.equals(actPay.getPay())) {
                res.setCode(1);
                res.setMessage("支付金额有误");
                return res;
            } else {
                BigDecimal amountNumber = actPay.getPay().multiply(new BigDecimal(100));// 总金额
                int money = amountNumber.intValue();
                String noncestr = UuidUtil.get32UUID();
                String body = "镇洋报名";
                String spbill_create_ip = IpUtil.ipAddress(request);//获取用户ip
                //组装参数，用户生成统一下单接口的签名
                Map<String, String> packageParams = new HashMap<String, String>();

                //组装参数，用户生成统一下单接口的签名
                packageParams.put("appid", Const.MINAPPID);
                packageParams.put("mch_id", Const.MCH_ID);
                packageParams.put("nonce_str", noncestr);
                packageParams.put("body", body);
                packageParams.put("out_trade_no", orderNo);//商户订单号
                packageParams.put("total_fee", money + "");//支付金额，这边需要转成字符串类型，否则后面的签名会失败
                packageParams.put("spbill_create_ip", spbill_create_ip);
                packageParams.put("notify_url", Const.NOTIFY_URL);//支付成功后的回调地址
                packageParams.put("trade_type", Const.TRADETYPE);//支付方式
                packageParams.put("openid", openId);
                String prestr = IpUtil.createLinkString(packageParams); // 把数组所有元素，按照“参数=参数值”的模式用“&”字符拼接成字符串

                //MD5运算生成签名，这里是第一次签名，用于调用统一下单接口
                String mysign = IpUtil.sign(prestr, Const.KEY, "utf-8").toUpperCase();

                //拼接统一下单接口使用的xml数据，要将上一步生成的签名一起拼接进去
                String xml = "<xml>" + "<appid>" + Const.MINAPPID + "</appid>" + "<body><![CDATA[" + body + "]]></body>" + "<mch_id>" + Const.MCH_ID + "</mch_id>" + "<nonce_str>" + noncestr + "</nonce_str>" + "<notify_url>" + Const.NOTIFY_URL + "</notify_url>" + "<openid>" + openId + "</openid>" + "<out_trade_no>" + orderNo + "</out_trade_no>" + "<spbill_create_ip>" + spbill_create_ip + "</spbill_create_ip>" + "<total_fee>" + money + "</total_fee>" + "<trade_type>" + Const.TRADETYPE + "</trade_type>" + "<sign>" + mysign + "</sign>" + "</xml>";

                System.out.println("调试模式_统一下单接口 请求XML数据：" + xml);

                //调用统一下单接口，并接受返回的结果
                String result = IpUtil.httpRequest(Const.PAY_URL, "POST", xml);

                System.out.println("调试模式_统一下单接口 返回XML数据：" + result);

                // 将解析结果存储在HashMap中
                Map map = IpUtil.doXMLParse(result);

                String return_code = (String) map.get("return_code");//返回状态码

                Map<String, Object> response = new HashMap<String, Object>();//返回给小程序端需要的参数
                if (return_code.equals("SUCCESS")) {
                    String prepay_id = (String) map.get("prepay_id");//返回的预付单信息
                    response.put("nonceStr", noncestr);
                    response.put("package", "prepay_id=" + prepay_id);
                    Long timeStamp = System.currentTimeMillis() / 1000;
                    response.put("timeStamp", timeStamp + "");//这边要将返回的时间戳转化成字符串，不然小程序端调用wx.requestPayment方法会报签名错误
                    //拼接签名需要的参数
                    String stringSignTemp = "appId=" + Const.MINAPPID + "&nonceStr=" + noncestr + "&package=prepay_id=" + prepay_id + "&signType=MD5&timeStamp=" + timeStamp;
                    //再次签名，这个签名用于小程序端调用wx.requesetPayment方法
                    String paySign = IpUtil.sign(stringSignTemp, Const.KEY, "utf-8").toUpperCase();
                    response.put("paySign", paySign);
                    response.put("appid", Const.MINAPPID);
                    res.setResult(response);
                }else {
                    res.setCode(1);
                    res.setMessage("支付失败");
                }
                return res;
            }
            //todo
        } catch (Exception e) {
            e.printStackTrace();
        }
        return res;
    }

    /**
     * @return
     * @throws Exception
     * @Description:微信支付回调
     */
    @GetMapping(value = "wxNotify")
    public void wxNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader((ServletInputStream) request.getInputStream()));
        String line = null;
        StringBuilder sb = new StringBuilder();
        while ((line = br.readLine()) != null) {
            sb.append(line);
        }
        br.close();
        //sb为微信返回的xml
        String notityXml = sb.toString();
        String resXml = "";
        System.out.println("接收到的报文：" + notityXml);

        Map map = IpUtil.doXMLParse(notityXml);


        String returnCode = (String) map.get("return_code");
        if ("SUCCESS".equals(returnCode)) {
            //验证签名是否正确
            Map<String, String> validParams = IpUtil.paraFilter(map);  //回调验签时需要去除sign和空值参数
            String validStr = IpUtil.createLinkString(validParams);//把数组所有元素，按照“参数=参数值”的模式用“&”字符拼接成字符串
            String sign = IpUtil.sign(validStr, Const.KEY, "utf-8").toUpperCase();//拼装生成服务器端验证的签名
            //根据微信官网的介绍，此处不仅对回调的参数进行验签，还需要对返回的金额与系统订单的金额进行比对等
            if (sign.equals(map.get("sign"))) {

                //此处添加自己的业务逻辑代码start
                String out_trade_no = map.get("out_trade_no") + "";//用户订单号
                QueryWrapper<ActPay> wrapper = new QueryWrapper<>(new ActPay());
                wrapper.eq("order_no", out_trade_no);
                ActPay order = payService.getOne(wrapper);//获取订单信息
//                ActUserRecord record = new ActUserRecord();
//                record.setStatus(1);
//                record.setActId(order.getActId());
//                record.setUserId(order.getUserId());
//                recordService.updateByActIdAndUserId(record);
                //修改微信支付订单状态
                order.setStatus(1);
                payService.updateById(order);


                //通知微信服务器已经支付成功
                resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>" + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
            }
        } else {
            resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
        }
        System.out.println(resXml);
        System.out.println("微信支付回调数据结束");

        BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());
        out.write(resXml.getBytes());
        out.flush();
        out.close();
    }

    @ApiOperation("我的订单list")
    @GetMapping("myOrderList")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "pageNo", value = "页码", defaultValue = "1"),
            @ApiImplicitParam(name = "pageSize", value = "条数", defaultValue = "10"),
            @ApiImplicitParam(name = "userId", value = "用户id", required = true),
            @ApiImplicitParam(name = "status", value = "0待支付 1已支付 2取消'", defaultValue = "1"),
    })
    public Result myOrderList(@RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
                              @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
                              String userId,
                              Integer status) {
        Result<IPage<ActPayVo>> result = new Result<>();

        // 活动id 活动url 活动标题 活动发起人 电话 订单创建时间 订单状态 订单号
        Page<ActPayVo> page = new Page<>(pageNo, pageSize);
        IPage<ActPayVo> pageList = payService.findByPage(page, userId, status);
        result.setResult(pageList);
        result.setSuccess(true);
        return result;

    }

    @ApiOperation(value = "订单详情",notes = "订单详情")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "orderNo",value = "订单号",required = true),
            @ApiImplicitParam(name = "userId",value = "用户id",required = true)
    })
    @GetMapping("orderDetail")
    public Result orderDetail(String orderNo,String userId){
        Result<ActPayVo> result = new Result<>();
        ActPayVo payVo = payService.detail(orderNo,userId);
        result.setResult(payVo);
        return result;
    }

}

